데이터 분석이란 용어는 상당히 광범위한 용어이므로 여기에서는 통계적 분석과 머신 러닝이라는 두가지 세부 영역에 국한하여 데이터 분석을 설명하도록 한다.
데이터 분석이란 어떤 데이터가 주어졌을 때
으로 볼 수 있다.
데이터 분석의 유형은 다양하다. 그 중 널리 사용되는 전형적인 방법으로는 예측(prediction), 클러스터링(clustering), 모사(approximation) 등이 있다.
예측은 어떤 특정한 유형의 입력 데이터가 주어지면 데이터 분석의 결과로 다른 유형의 데이터가 출력될 수 있는 경우이다. 예를 들어 다음과 같은 작업은 예측이라고 할 수 있다.
데이터 분석에서 말하는 예측이라는 용어는 시간상으로 미래의 의미는 포함하지 않는다. 시계열 분석에서는 시간상으로 미래의 데이터를 예측하는 경우가 있는데 이 경우에는 forecasting 이라는 용어를 사용한다.
클러스터링은 동일한 유형의 데이터가 주어졌을 때 유사한 데이터끼리 몇개의 집합으로 묶는 작업을 말한다. 예를 들어 다음과 같은 작업은 클러스터링이다.
모사는 대량의 데이터를 대표하는 소량의 데이터를 생성하는 작업이다.
만약 예측을 하고자 한다면 데이터의 유형을 입력 데이터와 출력 데이터라는 두 가지 유형의 데이터로 분류할 수 있어야 한다.
예측 작업에서 생성하고자 하는 데이터 유형을 출력 데이터라고 하고 이 출력 데이터를 생성하기 위해 사용되는 기반 데이터를 입력 데이터라고 한다. 회귀 분석에서는 독립 변수와 종속 변수라는 용어를 사용하며 머신 러닝에서는 일반적으로 feature와 target이라는 용어를 사용한다.
입력 데이터와 출력 데이터의 개념을 사용하여 예측 작업을 다시 설명하면 다음과 같다.
예측은 입력 데이터와 출력 데이터 사이의 관계를 분석하고 분석한 관계를 이용하여 출력 데이터가 아직 없거나 혹은 가지고 있는 출력 여러가지 이유로 부정확하다고 생각될 경우 보다 합리적인 출력값을 추정하는 것이다. 따라서 입력 데이터와 출력 데이터의 관계에 대한 분석이 완료된 이후에는 출력 데이터가 필요 없어도 일단 관계를 분석하기 위해서는 입력 데이터와 출력 데이터가 모두 존재해야 한다.
예측 작업에서 생성하고자 하는 데이터 유형을 출력 데이터라고 하고 이 출력 데이터를 생성하기 위해 사용되는 기반 데이터를 입력 데이터라고 한다.
예측은 입력 데이터와 출력 데이터 사이의 관계를 분석하고 분석한 관계를 이용하여 출력 데이터가 아직 없거나 혹은 가지고 있는 출력 여러가지 이유로 부정확하다고 생각될 경우 보다 합리적인 출력값을 추정하는 것이다. 따라서 입력 데이터와 출력 데이터의 관계에 대한 분석이 완료된 이후에는 출력 데이터가 필요 없어도 일단 관계를 분석하기 위해서는 입력 데이터와 출력 데이터가 모두 존재해야 한다.
입력 데이터와 출력 데이터의 개념을 사용하여 예측 작업을 다시 설명하면 다음과 같다.
통계적 분석이나 머신 러닝 등의 데이터 분석에 사용되는 데이터의 유형은 다음 숫자 혹은 카테고리 값 중 하나이어야 한다.
숫자와 카테고리 값의 차이점은 두 개의 데이터가 있을 때 이들의 크기나 혹은 순서를 비교할 수 있는가 없는가의 차이이다. 예를 들어 10kg과 23kg이라는 두 개의 무게는 23이 "크다"라고 크기를 비교하는 것이 가능하다. 그러나 "홍길동"과 "이순신"이라는 두 개의 카테고리 값은 크기를 비교할 수 없다.
일반적으로 카테고리 값은 가질 수 있는 경우의 수가 제한되어 있다. 이러한 경우의 수를 클래스(class)라고 부르는데 동전을 던진 결과와 같이 "앞면(head)" 혹은 "뒷면(tail)"처럼 두 가지 경우만 가능하면 이진 클래스(binary class)라고 한다. 주사위를 던져서 나온 숫자와 같이 세 개 이상의 경우가 가능하면 다중 클래스(multi class)라고 한다.
카테고리값처럼 비 연속적이지만 숫자처럼 비교 가능한 경우도 있을 수 있다. 예를 들어 학점이 "A", "B", "C", "D"와 같이 표시되는 경우는 비 연속적이고 기호로 표시되지만 크기 혹은 순서를 비교할 수 있다. 이러한 경우는 서수형(ordinal) 자료라고 하며 분석의 목표에 따라 숫자로 표기하기도 하고 일반적인 카테고리값으로 표기하기도 한다.
숫자가 아닌 이미지나 텍스트 정보는 분석에 목표에 따라 숫자나 카테고리 값으로 변환해야 한다. 이 때 해당하는 원본 정보를 손실 없이 그대로 숫자나 카테고리 값으로 바꿀 수도 있지만 대부분의 경우에는 분석에 필요한 핵심적인 정보만을 뽑아낸다. 이러한 과정은 데이터의 전처리(preprocessing)에 해당한다.
In [1]:
from sklearn.datasets import load_digits
digits = load_digits()
plt.imshow(digits.images[0], interpolation='nearest');
plt.grid(False)
In [2]:
digits.images[0]
Out[2]:
In [3]:
from sklearn.datasets import fetch_20newsgroups
news = fetch_20newsgroups()
print(news.data[0])
In [4]:
from sklearn.feature_extraction.text import TfidfVectorizer
vec = TfidfVectorizer(stop_words="english").fit(news.data[:100])
data = vec.transform(news.data[:100])
data
Out[4]:
In [5]:
plt.imshow(data.toarray()[:,:200], interpolation='nearest');
예측도 출력 데이터가 숫자인가 카테고리 값인가에 따라 회귀 분석(regression analysis)과 분류(classification)로 구분된다.
X=Real | X=Category | |
---|---|---|
Y=Real | Regression | ANOVA |
Y=Category | Classification | Classification |
In [6]:
from sklearn.datasets import load_boston
boston = load_boston()
print(boston.DESCR)
In [7]:
df = pd.DataFrame(boston.data, columns=boston.feature_names)
df["MEDV"] = boston.target
df.tail()
Out[7]:
In [8]:
sns.pairplot(df[["MEDV", "RM", "AGE", "DIS"]]);
In [9]:
from sklearn.linear_model import LinearRegression
predicted = LinearRegression().fit(boston.data, boston.target).predict(boston.data)
plt.scatter(boston.target, predicted, c='r', s=20);
plt.xlabel("Target");
plt.ylabel("Predicted");
setosa | versicolor | virginica |
---|---|---|
In [10]:
from sklearn.datasets import load_iris
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
sy = pd.Series(iris.target, dtype="category")
sy = sy.cat.rename_categories(iris.target_names)
df['species'] = sy
df.tail()
Out[10]:
In [11]:
sns.pairplot(df, hue="species");
In [12]:
from sklearn.cross_validation import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
X = iris.data[:, [2,3]]
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
model = SVC(kernel="linear", C=1.0, random_state=0)
model.fit(X_train_std, y_train)
XX_min = X_train_std[:, 0].min() - 1; XX_max = X_train_std[:, 0].max() + 1;
YY_min = X_train_std[:, 1].min() - 1; YY_max = X_train_std[:, 1].max() + 1;
XX, YY = np.meshgrid(np.linspace(XX_min, XX_max, 1000), np.linspace(YY_min, YY_max, 1000))
ZZ = model.predict(np.c_[XX.ravel(), YY.ravel()]).reshape(XX.shape)
cmap = mpl.colors.ListedColormap(sns.color_palette("Set2"))
plt.contourf(XX, YY, ZZ, cmap=cmap)
plt.scatter(X_train_std[y_train == 0, 0], X_train_std[y_train == 0, 1], c=cmap.colors[0], s=100)
plt.scatter(X_train_std[y_train == 1, 0], X_train_std[y_train == 1, 1], c=cmap.colors[2], s=100)
plt.scatter(X_train_std[y_train == 2, 0], X_train_std[y_train == 2, 1], c=cmap.colors[1], s=100)
plt.xlim(XX_min, XX_max);
plt.ylim(YY_min, YY_max);
In [15]:
from sklearn.cluster import DBSCAN
from sklearn.datasets.samples_generator import make_blobs
from sklearn.preprocessing import StandardScaler
X, labels_true = make_blobs(n_samples=750, centers=[[1, 1], [-1, -1], [1, -1]], cluster_std=0.4, random_state=0)
X = StandardScaler().fit_transform(X)
db = DBSCAN(eps=0.3, min_samples=10).fit(X)
n_clusters_ = len(set(db.labels_)) - (1 if -1 in db.labels_ else 0)
unique_labels = set(db.labels_)
f = plt.figure()
f.add_subplot(1,2,1)
plt.plot(X[:, 0], X[:, 1], 'o', markerfacecolor='k', markeredgecolor='k', markersize=10)
plt.title('Raw Data')
f.add_subplot(1,2,2)
colors = plt.cm.Spectral(np.linspace(0, 1, len(unique_labels)))
for k, col in zip(unique_labels, colors):
if k == -1: col = 'k'
class_member_mask = (db.labels_ == k)
xy = X[class_member_mask]
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=col, markeredgecolor='k', markersize=10);
plt.title('Estimated number of clusters: %d' % n_clusters_);
In [14]:
from sklearn.cluster import KMeans
from sklearn.metrics import pairwise_distances_argmin
from sklearn.datasets import load_sample_image
from sklearn.utils import shuffle
n_colors = 64
china = load_sample_image("china.jpg")
china = np.array(china, dtype=np.float64) / 255
w, h, d = original_shape = tuple(china.shape)
assert d == 3
image_array = np.reshape(china, (w * h, d))
image_array_sample = shuffle(image_array, random_state=0)[:1000]
kmeans = KMeans(n_clusters=n_colors, random_state=0).fit(image_array_sample)
labels = kmeans.predict(image_array)
def recreate_image(codebook, labels, w, h):
d = codebook.shape[1]
image = np.zeros((w, h, d))
label_idx = 0
for i in range(w):
for j in range(h):
image[i][j] = codebook[labels[label_idx]]
label_idx += 1
return image
print("{0:,} bytes -> {1:,} bytes : {2:5.2f}%".format(image_array.nbytes, labels.nbytes, float(labels.nbytes) / image_array.nbytes * 100.0))
f = plt.figure()
ax1 = f.add_subplot(1,2,1)
plt.axis('off')
plt.title('Original image (96,615 colors)')
ax1.imshow(china);
ax2 = f.add_subplot(1,2,2)
plt.axis('off')
plt.title('Quantized image (64 colors, K-Means)')
ax2.imshow(recreate_image(kmeans.cluster_centers_, labels, w, h));